﻿using Microsoft.Extensions.Localization;
using PHMEE.Constants;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Xml.Linq;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;

namespace PHMEE
{
    /// <summary>
    /// 机组
    /// </summary>
    public abstract class Unit : CreationAuditedEntity<Guid>
    {
        protected Unit()
        {

        }

        public Unit(Guid id, Guid vesselId, string name, string nameen, int number) : base(id)
        {

            VesselId = vesselId;
            SetName(name);
            SetNameEn(nameen);
            SetNumber(number);
        }


        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// 英文名
        /// </summary>
        public string NameEn { get; private set; }

        /// <summary>
        /// 编号
        /// </summary>
        public int Number { get; private set; }

        /// <summary>
        /// 标签
        /// </summary>
        public string Tags { get; set; }

        /// <summary>
        /// 区域
        /// </summary>
        public string Area { get; set; }

        /// <summary>
        /// 类型
        /// </summary>
        public UnitEnum Type { get; set; }

        /// <summary>
        /// 诊断阈值
        /// </summary>
        public double? Threshold { get; set; }

        public Guid VesselId { get; set; }

        public string Language => CultureInfo.CurrentCulture.TwoLetterISOLanguageName;

        /// <summary>
        /// 多语言展示Name
        /// </summary>
        public string DisplayName => GetLocalizedName();

        public ICollection<Equipment> Equipments { get; set; } = new List<Equipment>();

        public Dictionary<string, object> DerivedPropertiesJson { get; set; } = new Dictionary<string, object>();

        public abstract void SerializeProperties(Dictionary<string, object> derivedPropertiesJson);
        public abstract void DeserializeProperties();

        public abstract Dictionary<string, object> InitDefaultProperties();

        public Unit SetName(string name)
        {
            Name = Check.NotNullOrEmpty(name, nameof(name), UnitConst.MaxNameLength);
            return this;
        }

        public Unit SetNameEn(string nameen)
        {
            NameEn = Check.NotNullOrEmpty(nameen, nameof(nameen), UnitConst.MaxNameLength);
            return this;
        }

        public Unit SetNumber(int number)
        {
            Number = number;
            return this;
        }

        public Unit AddEquipment(Guid equipmentId, string name, string nameen, int number, EquipmentEnum type, Action<Equipment> action, IStringLocalizer L)
        {
            var (expression, localizedName) = GetEquipmentExpression(name, nameen);

            if (Equipments.Where(expression.Compile()).Any(item => item.Number == number))
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.EquipmentNameAlreadyExist], PHMEEDomainErrorCodes.EquipmentNameAlreadyExist).WithData("Name", localizedName).WithData("Number", number);
            }
            Equipment equipment = null;
            switch (type)
            {
                case EquipmentEnum.AsynElectricMotor:
                    equipment = new AsynElectricMotor(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.CentrifugalFan:
                    equipment = new CentrifugalFan(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.CentrifugalPump:
                    equipment = new CentrifugalPump(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.FuelOilSeparatorGear:
                    equipment = new FuelOilSeparatorGear(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.LubricatingOilSeparatorGear:
                    equipment = new LubricatingOilSeparatorGear(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.MainEngine:
                    equipment = new MainEngine(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.MainGenerator:
                    equipment = new MainGenerator(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.MainGeneratorDiesel:
                    equipment = new MainGeneratorDiesel(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.ReciprocatingCompressor:
                    equipment = new ReciprocatingCompressor(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.Turbocharger:
                    equipment = new Turbocharger(equipmentId, this.Id, name, nameen, number);
                    break;
                case EquipmentEnum.ShaftSystem:
                    equipment = new ShaftSystem(equipmentId, this.Id, name, nameen, number);
                    break;
            }
            action?.Invoke(equipment);

            Equipments.Add(equipment);

            return this;
        }

        public Unit UpdateEquipment(Guid equipmentId, string name, string nameen, Action<Equipment> action, IStringLocalizer L)
        {
            var (expression, localizedName) = GetEquipmentExpression(name, nameen);

            if (Equipments.Where(expression.Compile()).Any(item => item.Id != equipmentId))
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.EquipmentNameAlreadyExist], PHMEEDomainErrorCodes.EquipmentNameAlreadyExist).WithData("Name", localizedName);
            }
            var equipment = Equipments.FirstOrDefault(item => item.Id == equipmentId);
            if (equipment == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.EquipmentNotFound], PHMEEDomainErrorCodes.EquipmentNotFound);
            }

            action?.Invoke(equipment);

            return this;
        }

        public Unit RemoveEquipment(Guid equipmentId, IStringLocalizer L)
        {
            var equipment = Equipments.FirstOrDefault(item => item.Id == equipmentId);
            if (equipment == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.EquipmentNotFound], PHMEEDomainErrorCodes.EquipmentNotFound);
            }

            Equipments.Remove(equipment);

            return this;
        }

        public Equipment GetEquipment(Guid equipmentId, IStringLocalizer L)
        {
            var equipment = Equipments.FirstOrDefault(item => item.Id == equipmentId);
            if (equipment == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.EquipmentNotFound], PHMEEDomainErrorCodes.EquipmentNotFound);
            }

            return equipment;
        }

        public List<EquipmentEnum> GetEquipmentTypeOptions()
        {
            var dict = GetUnitToEquipmentOptions();

            if (dict.TryGetValue(this.Type, out var equipmentList))
            {
                return equipmentList;
            }
            return new List<EquipmentEnum>(); // 返回空列表，如果没有匹配项

        }

        public static Dictionary<UnitEnum, List<EquipmentEnum>> GetUnitToEquipmentOptions()
        {
            var dict = new Dictionary<UnitEnum, List<EquipmentEnum>>
            {
                { UnitEnum.BallastPumpUnit, new List<EquipmentEnum> { EquipmentEnum.CentrifugalPump, EquipmentEnum.AsynElectricMotor } },
                { UnitEnum.CombustionAirBlowerUnit, new List<EquipmentEnum> { EquipmentEnum.CentrifugalFan, EquipmentEnum.AsynElectricMotor } },
                { UnitEnum.FuelOilSeparatorUnit, new List<EquipmentEnum> { EquipmentEnum.FuelOilSeparatorGear, EquipmentEnum.AsynElectricMotor } },
                { UnitEnum.LubricatingOilPumpUnit, new List<EquipmentEnum> { EquipmentEnum.CentrifugalPump, EquipmentEnum.AsynElectricMotor } },
                { UnitEnum.LubricatingOilSepaUnit, new List<EquipmentEnum> { EquipmentEnum.LubricatingOilSeparatorGear, EquipmentEnum.AsynElectricMotor } },
                { UnitEnum.MainEngineUnit, new List<EquipmentEnum> { EquipmentEnum.MainEngine, EquipmentEnum.Turbocharger,EquipmentEnum.ShaftSystem } },
                { UnitEnum.MainGeneratorUnit, new List<EquipmentEnum> { EquipmentEnum.MainGeneratorDiesel, EquipmentEnum.MainGenerator } },
                { UnitEnum.SeaWaterPumpUnit, new List<EquipmentEnum> { EquipmentEnum.CentrifugalPump, EquipmentEnum.AsynElectricMotor } },
                { UnitEnum.StartingAirCompressUnit, new List<EquipmentEnum> { EquipmentEnum.ReciprocatingCompressor, EquipmentEnum.AsynElectricMotor } }
            };

            return dict;
        }

        public List<BaseInfoTagEnum> GetUnitTagOptions()
        {
            var list = new List<BaseInfoTagEnum>();

            if (!string.IsNullOrEmpty(Tags))
            {
                var arr = Tags.Split(',', StringSplitOptions.RemoveEmptyEntries);

                foreach (var tag in arr)
                {
                    if (Enum.TryParse(tag, out BaseInfoTagEnum result))
                    {
                        list.Add(result);
                    }
                }
            }

            return list;
        }

        public static List<BaseInfoTagEnum> GetLevelTagOptions()
        {
            var list = new List<BaseInfoTagEnum>
            {

            };

            return list;

        }

        public (Expression<Func<Equipment, bool>> Expression, string LocalizedName) GetEquipmentExpression(string name, string nameen)
        {
            Expression<Func<Equipment, bool>> expression = item => true;

            string localizedName = string.Empty;

            switch (Language)
            {
                case PhmeeConst.LanguageEn:

                    localizedName = nameen;

                    expression = expression.And(item => item.NameEn == nameen);

                    break;
                default:

                    localizedName = name;

                    expression = expression.And(item => item.Name == name);

                    break;
            }

            return (expression, localizedName);
        }

        private string GetLocalizedName()
        {
            string localizedName = Language switch
            {
                PhmeeConst.LanguageEn => NameEn,
                _ => Name
            };

            return localizedName;
        }


    }
}
